﻿# coding: utf-8

import Engine
import Camera

import wx

import wx.lib.agw.flatmenu as FM
from wx.lib.agw.artmanager import ArtManager, RendererBase, DCSaver
from wx.lib.agw.fmresources import ControlFocus, ControlPressed
from wx.lib.agw.fmresources import FM_OPT_SHOW_CUSTOMIZE, FM_OPT_SHOW_TOOLBAR, FM_OPT_MINIBAR
import wx.lib.agw.aui as aui

import Panel
from wxDialogGlobalSetting import wxDialogGlobalSetting

class wxMainFrame(wx.Frame):
    __PANEL_CREATE_LIST = [
        {'id' : ID_PANEL_MODEL, 'class' : wx.Panel, 'title' : TD.PANEL_MODEL, 'icon' : IL.ID_IMAGE_MODEL},
        {'id' : ID_PANEL_BROWSE, 'class' : Panel.wxPanelBrowse, 'title' : TD.PANEL_BROWSE, 'icon' : IL.ID_IMAGE_BROWSE},
        {'id' : ID_PANEL_MESH, 'class' : Panel.wxPanelMesh, 'title' : TD.PANEL_MESH, 'icon' : IL.ID_IMAGE_MESH},
        {'id' : ID_PANEL_ANIMATION, 'class' : Panel.wxPanelAnimation, 'title' : TD.PANEL_ANIMATION, 'icon' : IL.ID_IMAGE_ANIMATION},
        {'id' : ID_PANEL_PYTHON_SHELL, 'class' : Panel.wxPanelPythonShell, 'title' : TD.PANEL_PYTHON_SHELL, 'icon' : IL.ID_IMAGE_PYTHON_SHELL},
    ]
    
    __PANEL_MENU_CREATE_LIST = [
        {'id' : ID_PANEL_MODEL, 'title' : TD.MENU_VIEW_MODEL, 'icon' : IL.ID_IMAGE_MODEL},
        {'id' : ID_PANEL_BROWSE, 'title' : TD.MENU_VIEW_BROWSE, 'icon' : IL.ID_IMAGE_BROWSE},
        {'id' : ID_PANEL_MESH, 'title' : TD.MENU_VIEW_MESH, 'icon' : IL.ID_IMAGE_MESH},
        {'id' : ID_PANEL_ANIMATION, 'title' : TD.MENU_VIEW_ANIMATION, 'icon' : IL.ID_IMAGE_ANIMATION},
        {'id' : ID_PANEL_PYTHON_SHELL, 'title' : TD.MENU_VIEW_PYTHON_SHELL, 'icon' : IL.ID_IMAGE_PYTHON_SHELL}, 
    ]
    
    def __init__(self):
        wx.Frame.__init__(self, None, -1, TD.APP_NAME, size = (800, 600), 
            style = wx.DEFAULT_FRAME_STYLE|wx.MAXIMIZE)

        # data define.
        self._panelList = {}
        self._bitmapList = {}
        self._mouseMiddleDownPos = None
        self._mouseRightDownPos = None
        self._isMouseCaptured = False

        # Set application icon.
        self.SetIcon(wx.Icon('Resource/icon/main.ico', wx.BITMAP_TYPE_ICO))
        
        # Create PyAUI system.
        self._auiManager = aui.AuiManager(self)
        
        # Create main menu
        self.__CreateMainMenu()
        
        # Create tool bar
        self.__CreateToolBar()
        
        # Create all views
        self.__CreateAllViews()
        
        # Bind all events
        self.__BindAllEvents()
        
        # Put all views into PyAUI system.
        self.__CombineAll()
        
    def __CreateToolBar(self):
        self.__CreateToolBarPanel()
        
    def __CreateToolBarPanel(self):
        self._toolBarPanel = aui.AuiToolBar(self, wx.NewId(), style = aui.AUI_TB_DEFAULT_STYLE|aui.AUI_TB_OVERFLOW)
        self._toolBarPanel.SetToolBitmapSize(wx.Size(IL.IMAGE_BIG, IL.IMAGE_BIG))
        for item in wxMainFrame.__PANEL_CREATE_LIST:
            self._toolBarPanel.AddSimpleTool(item['id'], '', IL.GetBitmap(item['icon'], IL.IMAGE_BIG), short_help_string = item['title'], kind = aui.ITEM_CHECK)
        self._toolBarPanel.Realize()
                                      
    def __CreateMainMenuPanel(self, menu, itemList):        
        for item in itemList:
            id = item['id']
            if id == None:
                subMenu = FM.FlatMenu()
                menu.AppendItem(FM.FlatMenuItem(menu, wx.NewId(), item['title'], subMenu = subMenu))
                self.__CreateMainMenuPanel(subMenu, item['child'])
            else:
                menu.AppendItem(FM.FlatMenuItem(menu, id, item['title'], normalBmp = IL.GetBitmap(item['icon'], IL.IMAGE_SMALL), kind = wx.ITEM_CHECK))
                        
    def __CreateMainMenu(self):
        # Create menu bar.
        self._menuBar = FM.FlatMenuBar(self, wx.ID_ANY, 32, 2, options = FM_OPT_SHOW_CUSTOMIZE)
        menuFile = FM.FlatMenu()
        menuView = FM.FlatMenu()
        menuHelp = FM.FlatMenu()
        
        self._menuBar.Append(menuFile, TD.MENU_FILE)
        self._menuBar.Append(menuView, TD.MENU_VIEW)
        self._menuBar.Append(menuHelp, TD.MENU_HELP)
                
        # Create file menu
        self._idMenuFileNewModel = wx.NewId()
        self._idMenuFileLoadModel = wx.NewId()
        self._idMenuFileSaveModel = wx.NewId()
        self._idMenuFileSaveModelAs = wx.NewId()
        self._idMenuFileGlobalSetting = wx.NewId()
        self._idMenuFileExit = wx.NewId()
        
        menuFile.AppendItem(FM.FlatMenuItem(menuFile, self._idMenuFileNewModel, TD.MENU_FILE_NEW_MODEL, normalBmp = IL.GetBitmap(IL.ID_IMAGE_FILE_NEW, IL.IMAGE_SMALL)))
        menuFile.AppendItem(FM.FlatMenuItem(menuFile, self._idMenuFileLoadModel, TD.MENU_FILE_LOAD_MODEL))
        menuFile.AppendItem(FM.FlatMenuItem(menuFile, self._idMenuFileSaveModel, TD.MENU_FILE_SAVE_MODEL))
        menuFile.AppendItem(FM.FlatMenuItem(menuFile, self._idMenuFileSaveModelAs, TD.MENU_FILE_SAVE_MODEL_AS))
        menuFile.AppendSeparator()
        menuFile.AppendItem(FM.FlatMenuItem(menuFile, self._idMenuFileGlobalSetting, TD.MENU_FILE_GLOBAL_SETTING, normalBmp = IL.GetBitmap(IL.ID_IMAGE_SETTING, IL.IMAGE_SMALL)))
        menuFile.AppendSeparator()
        menuFile.AppendItem(FM.FlatMenuItem(menuFile, self._idMenuFileExit, TD.MENU_FILE_EXIT, normalBmp = IL.GetBitmap(IL.ID_IMAGE_EXIT, IL.IMAGE_SMALL)))
        
        # Create view menu
        self.__CreateMainMenuPanel(menuView, wxMainFrame.__PANEL_MENU_CREATE_LIST)
        
        # Create help menu.
        self._idMenuHelpTopics = wx.NewId()
        self._idMenuHelpAbout = wx.NewId()
        
        menuHelp.AppendItem(FM.FlatMenuItem(menuHelp, self._idMenuHelpTopics, TD.MENU_HELP_TOPICS))
        menuHelp.AppendItem(FM.FlatMenuItem(menuHelp, self._idMenuHelpAbout, TD.MENU_HELP_ABOUT))
        
        self._menuBar.Refresh()
        self._menuBar.UpdateAcceleratorTable()
        
    def __CreateAllViews(self):
        self._mainNotebook = aui.AuiNotebook(self, wx.NewId(), wx.DefaultPosition, wx.DefaultSize, WS.MAIN_FRAME_NOTEBOOK_STYLE);
        self._mainNotebook.SetArtProvider(aui.ChromeTabArt())
        
        for item in wxMainFrame.__PANEL_CREATE_LIST:
            id = item['id']
            title = item['title']
            classType = item['class']
            icon = item['icon']
            panel = classType(self, id)
            panel.SetLabel(title)
            panel.icon = icon
            self._panelList[id] = panel
            self.__AddPanel(panel)
                                        
    def __AddPanel(self, panel):
        self._mainNotebook.AddPage(panel, panel.GetLabel(), False, IL.GetBitmap(panel.icon, IL.IMAGE_SMALL))
        panel.Show()
        self._mainNotebook.Update()
        
    def __RemovePanel(self, idx):
        page = self._mainNotebook.GetPage(idx)
        page.Hide()
        self._mainNotebook.RemovePage(idx)
        self._mainNotebook.Update()
        
    def __BindEventPanel(self, itemList):       
        for item in itemList:
            id = item['id']
            if id == None:
                self.__BindEventPanel(item['child'])
            else:
                self.Bind(wx.EVT_MENU, self.__OnMenuClick, id = id)
                self.Bind(wx.EVT_UPDATE_UI, self.__OnMenuUpdateUI, id = id)
                        
    def __BindAllEvents(self):
        self.Bind(wx.EVT_CLOSE, self.__OnClose)
        
        self._mainNotebook.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.__OnPanelClose)
        
        self.__BindEventPanel(wxMainFrame.__PANEL_MENU_CREATE_LIST)
        
        modelPanel = self._panelList[ID_PANEL_MODEL]
        modelPanel.Bind(wx.EVT_SIZE, self.__OnWindowResize)
        modelPanel.Bind(wx.EVT_RIGHT_DOWN, self.__OnMouseRightDown)
        modelPanel.Bind(wx.EVT_RIGHT_UP, self.__OnMouseRightUp)
        modelPanel.Bind(wx.EVT_MIDDLE_DOWN, self.__OnMouseMiddleDown)
        modelPanel.Bind(wx.EVT_MIDDLE_UP, self.__OnMouseMiddleUp)
        modelPanel.Bind(wx.EVT_LEFT_DOWN, self.__OnMouseLeftDown)
        modelPanel.Bind(wx.EVT_LEFT_UP, self.__OnMouseLeftUp)
        modelPanel.Bind(wx.EVT_MOTION, self.__OnMouseMotion)
        modelPanel.Bind(wx.EVT_MOUSEWHEEL, self.__OnMouseWheel)     
        modelPanel.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.__OnMouseCaptureLost)
        
        # Menu event.
        self.Bind(wx.EVT_MENU, self.__OnCmdFileGlobalSetting, id = self._idMenuFileGlobalSetting)       

    def __OnMenuClick(self, e):
        panel = self._panelList.get(e.GetId(), None)
        idx = self._mainNotebook.GetPageIndex(panel)
        if wx.NOT_FOUND == idx:
            self.__AddPanel(panel)
        else:
            self.__RemovePanel(idx)
        
    def __OnMenuUpdateUI(self, e):
        panel = self._panelList.get(e.GetId(), None)            
        if wx.NOT_FOUND == self._mainNotebook.GetPageIndex(panel):
            e.Check(False)
        else:
            e.Check(True)           
        
    def __OnPanelClose(self, e):
        idx = e.GetSelection()
        self.__RemovePanel(idx)
        e.Veto()
    
    def __CombineAll(self):
        self._auiManager.AddPane(self._mainNotebook, aui.AuiPaneInfo().CenterPane().PaneBorder(False))
        self.__PositionMenuBarAUI(self._auiManager)
        self._auiManager.AddPane(self._toolBarPanel, aui.AuiPaneInfo().ToolbarPane().Top().Row(1).Position(1))

        if GLOBAL_SETTING._general._perspective:
            self._mainNotebook.LoadPerspective(GLOBAL_SETTING._general._perspective)
        
        self._auiManager.Update()
    
    def __PositionMenuBarAUI(self, fixToolbar = True):
        pn = aui.AuiPaneInfo()
        xx = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X)
        
        # We add our menu bar as a toolbar, with the following settings
        pn.Name("flat_menu_bar")
        pn.Caption("Menu Bar")
        pn.Top()
        pn.MinSize(wx.Size(xx/2, self._menuBar._barHeight))
        pn.LeftDockable(False)
        pn.RightDockable(False)
        pn.ToolbarPane()
        if not fixToolbar:
            # We add our menu bar as a toolbar, with the following settings
            pn.BestSize(wx.Size(xx, self._menuBar._barHeight))
            pn.FloatingSize(wx.Size(300, self._menuBar._barHeight))
            pn.Floatable(True)
            pn.MaxSize(wx.Size(xx, self._menuBar._barHeight))
            pn.Gripper(True)
            
        else:
            pn.BestSize(wx.Size(xx, self._menuBar._barHeight))
            pn.Gripper(False)
        
        pn.Resizable(False)
        self._auiManager.AddPane(self._menuBar, pn)
            
    def __OnClose(self, e):
        wx.GetApp()._keepGoing = False
        GLOBAL_SETTING._general._perspective = self._mainNotebook.SavePerspective()
        self._auiManager.UnInit()
        self.Destroy()
        e.Skip()

    def __OnWindowResize(self, e):
        if wx.GetApp()._keepGoing:
            hWnd = self._panelList[ID_PANEL_MODEL].GetHandle()
            Engine.OnRenderWindowResize(hWnd)
            
    def __OnMouseRightDown(self, e):
        self._panelList[ID_PANEL_MODEL].CaptureMouse()
        self._isMouseCaptured = True
        self._mouseRightDownPos = e.GetPosition()
        
    def __OnMouseRightUp(self, e):
        if self._isMouseCaptured:
            self._panelList[ID_PANEL_MODEL].ReleaseMouse()
            self._isMouseCaptured = False
        self._mouseRightDownPos = None

    def __OnMouseMiddleDown(self, e):
        self._panelList[ID_PANEL_MODEL].CaptureMouse()
        self._isMouseCaptured = True
        self._mouseMiddleDownPos = e.GetPosition()

    def __OnMouseMiddleUp(self, e):
        if self._isMouseCaptured:
            self._panelList[ID_PANEL_MODEL].ReleaseMouse()
            self._isMouseCaptured = False
        self._mouseMiddleDownPos = None
        
    def __OnMouseLeftDown(self, e):
        self._panelList[ID_PANEL_MODEL].SetFocus()
    
    def __OnMouseLeftUp(self, e):
        pass
        
    def __OnMouseMotion(self, e):
        if (not self._mouseMiddleDownPos and not self._mouseRightDownPos) or not e.Dragging():
            return

        pos = e.GetPosition()
        cam = Engine.GetCurrentCamera()
        if self._mouseRightDownPos:
            Camera.RotationAxisY(cam, -(pos[0] - self._mouseRightDownPos[0]) / 100.0)
            Camera.RotationViewX(cam, -(pos[1] - self._mouseRightDownPos[1]) / 100.0)
            Camera.Update(cam, 0)
            self._mouseRightDownPos = pos
        elif self._mouseMiddleDownPos:
            Camera.MoveViewX(cam, pos[0] - self._mouseMiddleDownPos[0])
            Camera.MoveAxisY(cam, pos[1] - self._mouseMiddleDownPos[1])
            Camera.Update(cam, 0)
            self._mouseMiddleDownPos = pos
    
    def __OnMouseWheel(self, e):
        cam = Engine.GetCurrentCamera()
        if e.m_altDown:
            Camera.MoveViewZ(cam, e.m_wheelRotation * 5)
        else:
            Camera.MoveViewZ(cam, e.m_wheelRotation / 2)        
            
    def __OnMouseCaptureLost(self, e):
        self._isMouseCaptured = False
            
    def __OnCmdFileGlobalSetting(self, e):
        dlg = wxDialogGlobalSetting(self)
        dlg.ShowModal()
        dlg.Destroy()           